﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Framework.Packets
{
    /// <summary>
    /// Packet creater.
    /// Inherites IPacketHandler.
    /// </summary>
    public class PacketWriter : IPacketHandler
    {
        /// <summary>
        /// MemoryStream we're using to create the buffer.
        /// </summary>
        private MemoryStream data;

        /// <summary>
        /// 
        /// </summary>
        public long Length { get { return data.Length; } }

        /// <summary>
        /// 
        /// </summary>
        private bool hLengthSet = false;

        /// <summary>
        /// 
        /// </summary>
        public byte[] Data
        {
            get
            {
                SetLength();
                return data.ToArray();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public IPacket Packet
        {
            get
            {
                SetLength();
                return new Packet() { Data = data.ToArray() };
            }
        }

        //private bool tLengthSet = false;

        /// <summary>
        /// 
        /// </summary>
        public PacketWriter()
        {
            data = new MemoryStream();
            //Set 0x0000 to header
            //Write((ushort)0);         // total len + header
            Write((byte)0);             // opcode
            Write((byte)0);             // total len
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="code"></param>
        public PacketWriter(ushort code)
        {
            data = new MemoryStream();
            //Write((ushort)0);         // total len + header
            Write((byte)code);          // opcode
            Write((byte)0);             // total len
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="code"></param>
        /// <param name="hLength"></param>
        public PacketWriter(ushort code, ushort hLength)
        {
            data = new MemoryStream();
            //Write((ushort)hLength);   // total len + header
            Write((byte)code);          // opcode
            Write((byte)hLength);       // total len
            hLengthSet = true;
        }

        /// <summary>
        /// 
        /// </summary>
        public void SetLength()
        {
            if (!hLengthSet)
            {
                data.Position = 2;
                data.Write(BitConverter.GetBytes(Convert.ToUInt16(data.Length - 2)), 0, 2);
            }
            //Console.WriteLine(data.Length - 2);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(byte appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 1);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(sbyte appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 1);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(short appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 2);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(ushort appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 2);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(int appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 4);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(uint appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 4);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(long appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 8);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(ulong appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 8);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(float appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 4);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(double appendix)
        {
            data.Write(BitConverter.GetBytes(appendix), 0, 8);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(byte[] appendix)
        {
            if (appendix == null)
            {
                throw new ArgumentNullException("appendix", "You're trying to append null.");
            }

            data.Write(appendix, 0, appendix.Length);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void Write(string appendix)
        {
            if (appendix == null)
            {
                throw new ArgumentNullException("appendix", "You're trying to append null.");
            }

            //Write length
            Write((ushort)appendix.Length);

            byte[] bytes = Encoding.ASCII.GetBytes(appendix);
            data.Write(bytes, 0, bytes.Length);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appendix"></param>
        public void WriteUnicode(string appendix)
        {
            if (appendix == null)
            {
                throw new ArgumentNullException("appendix", "You're trying to append null.");
            }

            //Write length
            Write((ushort)(appendix.Length * 2));

            byte[] bytes = Encoding.Unicode.GetBytes(appendix);
            data.Write(bytes, 0, bytes.Length);
        }

        /// <summary>
        /// 
        /// </summary>
        public void Close()
        {
            data.Close();
        }

        public enum StringEncoding { ASCII = 1, UNICODE = 2 }


        public int Position
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
    }
}
